


//按键消抖
module btn_dis_shake(
			
			input					clk,
			input					rst_n,
			
			
			input					ikey,				//按键输入
			output				okey				//按键输出

);

//模式
//0   按下生效，抬起，算一次
//1   按下抬起，算一次
//2	按下后，一段时间算一次
parameter			mode = 2;


localparam			S_IDLE		=		'd0;
localparam			S_DOWN		=		'd1;
localparam			S_DEALY		=		'd2;
localparam			S_UP			=		'd3;
localparam			S_DIS_SHAKE = 'd4;


localparam			DIS_SHAKE	=	'd6000;			//消抖延时
localparam			DELAY		=		'd50000;	//模式2中，一段时间

reg[3:0]			state	,		next_state;

wire 	neg_key,pos_key;	//按键下降沿上升沿
reg	key0,key1;			//按键状态储存

reg[30:0]		delay_cnt;

assign		neg_key 	=	key1 & (~key0);		//判断按键信号的下降沿
assign		pos_key	=	(~key1) & key0;		//判断按键信号的上升沿


//根据模式来判断按键输出
assign 	okey 	=	(mode == 0 &&  state == S_DIS_SHAKE && delay_cnt == DIS_SHAKE) ? 1'b1 : (mode == 1 && state == S_UP)?1'b1:(mode==2 && state == S_DEALY && delay_cnt == DELAY) ? 1'b1:1'b0;


always@(posedge clk or negedge rst_n)
begin
	if(rst_n  == 1'b0)
	begin
			key0 <= 1'b1;
			key1 <= 1'b1;
	end
	else
	begin
		key0 <= ikey;
		key1 <= key0;
	end
end

always@(posedge clk or negedge rst_n)
begin
	if(rst_n == 1'b0)
		state <= S_IDLE;
	else
		state <= next_state;
end

always@(*)
begin
	case(state)
		S_IDLE:
			if(neg_key	==	1'b1)
				next_state <= S_DIS_SHAKE;
			else
				next_state <= S_IDLE;
		S_DIS_SHAKE:			//按下消抖
				if(delay_cnt == DIS_SHAKE)
					next_state <= S_DEALY;
				else if(pos_key == 1'b1)
					next_state <= S_IDLE;
				else
					next_state <= S_DIS_SHAKE;
		S_DEALY:			//延时
			if(delay_cnt == DELAY	&& pos_key == 1'b1)
				next_state <= S_UP;
			else if( pos_key == 1'b1)
				next_state <= S_UP;
			else
				next_state <= S_DEALY;
		S_UP:
			next_state <= S_IDLE;
		default:	next_state <= S_IDLE;
	endcase
end


//延时计数
always@(posedge clk or negedge rst_n)
begin
	if(rst_n == 1'b0)
		delay_cnt <= 'd0;
	else if(state != next_state)
		delay_cnt  <= 'd0;
	else if(state == S_DIS_SHAKE)
		delay_cnt <= delay_cnt + 1'b1;
	else if(state == S_DEALY && delay_cnt == DELAY)
		delay_cnt <= 'd0;
	else if(state == S_DEALY)
		delay_cnt <= delay_cnt + 1'b1;
	else
		delay_cnt <= 'd0;
end


endmodule 